package com.jacky.iot;

import com.jacky.iot.resources.*;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.server.resources.ObservableResource;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.SystemConfig;
import org.eclipse.californium.elements.config.TcpConfig;
import org.eclipse.californium.elements.config.UdpConfig;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.GeneralSecurityException;
import java.util.concurrent.TimeUnit;

public class DemoServer extends CoapServer {
    static {
        CoapConfig.register();
        UdpConfig.register();
        DtlsConfig.register();
        TcpConfig.register();
        System.setProperty("COAP_ROOT_RESOURCE_NOTE",
                "Note: the data sent to this server is public visible to other\n" +
                        "      users! Don't send data, which requires data privacy.");
    }

    private static final File CONFIG_FILE = new File("CaliforniumPlugtest3.properties");
    private static final String CONFIG_HEADER = "Californium CoAP Properties file for AppServer Server";

    private static final int DEFAULT_MAX_RESOURCE_SIZE = 8192;
    private static final int DEFAULT_BLOCK_SIZE = 64;

    private NewAdvancedCertificateVerifier certificateVerifier;
    ObservableResource observableResource;
    static CoapServer coapServer;

    private static final Configuration.DefinitionsProvider DEFAULTS = new Configuration.DefinitionsProvider() {

        @Override
        public void applyDefinitions(Configuration config) {
            config.set(DtlsConfig.DTLS_CONNECTION_ID_LENGTH, 6);
            config.set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, false);
        }
    };

    public static void main(String[] args) throws IOException, GeneralSecurityException {
        Configuration configuration = init("127.0.0.1", 5683);
        coapServer.start();
    }

    public DemoServer(Configuration config) {
        // 这是支持observable的关键
        super(config);
        add(new DefaultTestResource("test"));
        add(new SeparateResource("separate"));
        add(new SegPathResource());
        add(new QueryResource("query"));
        add(new LocationQueryResource("location-query"));
        add(new MultiFormatResource("multi-format"));
        add(new CreateResource("create1"));
        add(new ValidateResource("validate"));
    }

    private static Configuration init(String host, Integer port) throws IOException, GeneralSecurityException {
//        Configuration netCfg = new Configuration();
//        netCfg.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, Boolean.TRUE);
//        netCfg.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, Boolean.TRUE);
//        netCfg.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, 300, TimeUnit.SECONDS);
//        netCfg.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
//        netCfg.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED);
//        netCfg.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024);
//        netCfg.set(CoapConfig.MAX_MESSAGE_SIZE, 1024);
//        netCfg.set(CoapConfig.MAX_RETRANSMIT, 4);
//        netCfg.set(CoapConfig.COAP_PORT, port);
//        CoapServer coapServer = new CoapServer(netCfg);

        Configuration configuration = Configuration.createWithFile(CONFIG_FILE, CONFIG_HEADER, new Configuration.DefinitionsProvider() {
            @Override
            public void applyDefinitions(Configuration config) {
                config.set(SystemConfig.HEALTH_STATUS_INTERVAL, 300, TimeUnit.SECONDS);
                config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, DEFAULT_MAX_RESOURCE_SIZE);
                config.set(CoapConfig.MAX_MESSAGE_SIZE, DEFAULT_BLOCK_SIZE);
                config.set(CoapConfig.PREFERRED_BLOCK_SIZE, DEFAULT_BLOCK_SIZE);
                config.set(CoapConfig.NOTIFICATION_CHECK_INTERVAL_COUNT, 4);
                config.set(CoapConfig.NOTIFICATION_CHECK_INTERVAL_TIME, 30, TimeUnit.SECONDS);
                config.set(CoapConfig.TCP_NUMBER_OF_BULK_BLOCKS, 1);
                config.set(CoapConfig.MAX_ACTIVE_PEERS, 10000);
                config.set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, false);
                config.set(DtlsConfig.DTLS_AUTO_HANDSHAKE_TIMEOUT, null, TimeUnit.SECONDS);
                config.set(DtlsConfig.DTLS_CONNECTION_ID_LENGTH, 6);
//            config.set(DtlsConfig.DTLS_PRESELECTED_CIPHER_SUITES, PRESELECTED_CIPHER_SUITES);
                config.set(DtlsConfig.DTLS_MAX_CONNECTIONS, 10000);
                config.set(DtlsConfig.DTLS_REMOVE_STALE_DOUBLE_PRINCIPALS, false);
                config.set(DtlsConfig.DTLS_MAC_ERROR_FILTER_QUIET_TIME, 4, TimeUnit.SECONDS);
                config.set(DtlsConfig.DTLS_MAC_ERROR_FILTER_THRESHOLD, 8);
                config.set(DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT, 3, TimeUnit.SECONDS);
                config.set(DtlsConfig.DTLS_ADDITIONAL_ECC_TIMEOUT, 8, TimeUnit.SECONDS);
                config.set(TcpConfig.TCP_CONNECT_TIMEOUT, 15, TimeUnit.SECONDS);
                config.set(TcpConfig.TCP_CONNECTION_IDLE_TIMEOUT, 60, TimeUnit.MINUTES);
                config.set(TcpConfig.TLS_HANDSHAKE_TIMEOUT, 60, TimeUnit.SECONDS);
            }
        });
        coapServer = new DemoServer(configuration);
        CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder();
        InetAddress addr = InetAddress.getByName(host);
        InetSocketAddress sockAddr = new InetSocketAddress(addr, port);
        noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);

        noSecCoapEndpointBuilder.setConfiguration(configuration);
        CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
        coapServer.addEndpoint(noSecCoapEndpoint);
        return configuration;
    }
}